﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace System.ServiceModel.Dynamic
{

    internal class ChannelFactoryManager<T>
    {

        private static readonly object _syncRoot = new object();

        private ChannelFactory<T> channelFactory;       
        private Func<ChannelFactory<T>> funcChannelFactory;
        private List<IEndpointBehavior> _behaviors;


        public ChannelFactoryManager(Func<ChannelFactory<T>> channelFactory)
        {
            this.funcChannelFactory = channelFactory;
            _behaviors = new List<IEndpointBehavior>();
        }


        public void Add(params IEndpointBehavior[] behaviors)
        {

            foreach (IEndpointBehavior item in behaviors)
                _behaviors.Add(item);

        }


        #region Channels

        internal T CreateChannel()
        {
            ChannelFactory<T> channel = GetFactory();
            T local = channel.CreateChannel();
            return local;
        }
        
        private ChannelFactory<T> GetFactory()
        {
            lock (_syncRoot)
            {
                ChannelFactory<T> factory = channelFactory ?? (channelFactory = CreateFactoryInstance());
                return factory;
            }
        }

        private ChannelFactory<T> CreateFactoryInstance()
        {

            ChannelFactory<T> factory = funcChannelFactory();

            foreach (var item in _behaviors)
                factory.Endpoint.Behaviors.Add(item);
            
            factory.Faulted += Factory_Faulted;
            factory.Open();

            return factory;

        }

        private void Factory_Faulted(object sender, EventArgs e)
        {

            ChannelFactory<T> c = sender as ChannelFactory<T>;

            try
            {
                c.Close();
            }
            catch (Exception)
            {
                c.Abort();
            }
            finally
            {
                GC.SuppressFinalize(channelFactory);               
            }

        }

        #endregion

        
    }

}
